﻿using Abp;
using Abp.Configuration;
using Abp.Runtime.Session;
using Castle.DynamicProxy;
using AbpProjectTemplate.Utilities;

namespace AbpProjectTemplate.Components.Configuration
{
    /// <summary>
    /// 自动配置拦截器，用于获取/修改配置值
    /// </summary>
    public class AutoSettingsInterceptor : IInterceptor
    {
        private readonly ISettingManager _settingManager;
        private readonly ISettingDefinitionManager _settingDefinitionManager;
        private readonly IAutoSettingsTenantAndUserProvider _autoSettingsTenantAndUserProvider;
        public AutoSettingsInterceptor(ISettingManager settingManager,
            ISettingDefinitionManager settingDefinitionManager,
            IAutoSettingsTenantAndUserProvider autoSettingsTenantAndUserProvider)
        {
            this._settingManager = settingManager;
            this._settingDefinitionManager = settingDefinitionManager;
            this._autoSettingsTenantAndUserProvider = autoSettingsTenantAndUserProvider;
            //this.AbpSession = NullAbpSession.Instance;
        }

        protected void PostProceed(IInvocation invocation)
        {
            var setFlag = "set_";
            var getFlag = "get_";

            var isSet = invocation.Method.Name.StartsWith(setFlag);
            var isGet = invocation.Method.Name.StartsWith(getFlag);
            //非属性方法不处理
            if (!isSet && !isGet)
                return;

            var pname = invocation.Method.Name.Replace(setFlag, "")
                                              .Replace(getFlag, "");
            var settingName = AutoSettingsUtils.CreateSettingName(invocation.TargetType, pname);
            //配置 设置
            if (isSet)
            {
                this.ChangeSettingValue(settingName, invocation.Arguments[0]?.ToString());
            }
            //配置 获取
            else
            {
                var val = this.GetSettingValue(settingName);
                invocation.ReturnValue = ConvertHelper.ChangeType(val, invocation.Method.ReturnType);
            }
        }

        protected object GetSettingValue(string settingName)
        {
            var settings = this._settingDefinitionManager.GetSettingDefinition(settingName);
            var tenantId = this._autoSettingsTenantAndUserProvider.TenantId;
            var userId = this._autoSettingsTenantAndUserProvider.UserId;
            if (settings.Scopes.HasFlag(SettingScopes.User) && userId.HasValue)
                return this._settingManager.GetSettingValueForUser(settingName, tenantId, userId.Value, true);
            else if (settings.Scopes.HasFlag(SettingScopes.Tenant) && tenantId.HasValue)
                return this._settingManager.GetSettingValueForTenant(settingName, tenantId.Value);
            return this._settingManager.GetSettingValue(settings.Name);
        }

        protected void ChangeSettingValue(string settingName, object value)
        {
            var settings = this._settingDefinitionManager.GetSettingDefinition(settingName);
            var val = value?.ToString();
            var tenantId = this._autoSettingsTenantAndUserProvider.TenantId;
            var userId = this._autoSettingsTenantAndUserProvider.UserId;
            if (settings.Scopes.HasFlag(SettingScopes.User) && userId.HasValue)
                this._settingManager.ChangeSettingForUser(new UserIdentifier(tenantId, userId.Value), settings.Name, val);
            else if (settings.Scopes.HasFlag(SettingScopes.Tenant) && tenantId.HasValue)
                this._settingManager.ChangeSettingForTenant(tenantId.Value, settings.Name, val);
            else
                this._settingManager.ChangeSettingForApplication(settings.Name, val);
        }

        public void Intercept(IInvocation invocation)
        {
            invocation.Proceed();
            this.PostProceed(invocation);
        }
    }
}
